package com.sh.business.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.sh.business.config.RabbitmqSender;
import com.sh.business.domain.*;
import com.sh.business.domain.bo.AleoAddressBo;
import com.sh.business.domain.bo.AssetConvertBo;
import com.sh.business.domain.bo.SetComputilityBo;
import com.sh.business.domain.dto.FinancingErrorVo;
import com.sh.business.domain.form.ModifyPasswordBo;
import com.sh.business.domain.form.PasswordBo;
import com.sh.business.domain.form.TransferBo;
import com.sh.business.domain.form.UserLoginBo;
import com.sh.business.domain.vo.*;
import com.sh.business.mapper.*;
import com.sh.business.service.facade.TransactionServiceFacade;
import com.sh.business.service.facade.UserFoundServiceFacade;
import com.sh.business.service.facade.UserServiceFacade;
import com.sh.common.core.domain.model.LoginUser;
import com.sh.common.core.enums.*;
import com.sh.common.core.exception.ServiceException;
import com.sh.common.core.utils.*;
import com.sh.common.core.utils.ip.AddressUtils;
import com.sh.common.mybatis.core.page.TableDataInfo;
import com.sh.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sh.common.mybatis.helper.DataBaseHelper;
import com.sh.common.satoken.utils.LoginHelper;
import com.sh.system.service.ISysConfigService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.sh.business.domain.bo.UserBo;
import com.sh.business.service.IUserService;
import org.web3j.crypto.*;
import org.web3j.utils.Numeric;
import software.amazon.awssdk.services.s3.endpoints.internal.Value;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Stream;

import static com.sh.common.core.constant.BusinessConstants.BENEFIT_ID;
import static com.sh.common.core.constant.BusinessConstants.COMPANY_ID;

/**
 * 用户信息Service业务层处理
 *
 * @author ruoyi
 * @date 2024-10-09
 */
@RequiredArgsConstructor
@Service
public class UserServiceImpl implements IUserService {

    private final UserMapper baseMapper;
    private final UserFundDetailMapper userFundDetailMapper;
    private final ISysConfigService iSysConfigService;
    private final UserInvestMapper userInvestMapper;
    private final UserWithdrawalMapper userWithdrawalMapper;
    private final UserFoundServiceFacade userFoundServiceFacade;
    private final TransactionServiceFacade transactionServiceFacade;
    private final UserFinancingMapper userFinancingMapper;
    private final RabbitmqSender rabbitmqSender;

    public static final String PERSONAL_MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n";

    @Override
    public void recycleComputility(String orderSn) {
        UserInvest userInvest = userInvestMapper.queryByOrderSnAndDeleted(orderSn);
        // 扣除团队业绩
        User user = baseMapper.selectById(userInvest.getUserId());

        // 扣除本人业绩
        if (user.getSelfAchievement().compareTo(userInvest.getAmount()) > 0) {
            userFoundServiceFacade.changeUserFound(userInvest.getUserId(), UserFoundEnum.SELF_ACHIEVEMENT, TransferFlagEnum.TRANSFER_OUT, userInvest.getAmount());
        }


        List<Long> ancestorList = StringUtils.str2List(user.getAncestors(), StringUtils.SEPARATOR, false, false)
            .stream().map(Long::parseLong).toList();
        List<User> ancestorUserList = baseMapper.selectBatchIds(ancestorList);
        // 翻转、按照最近的在前
        Collections.reverse(ancestorUserList);

        // 团队业绩奖励
        ancestorUserList.forEach(currentUser -> {
            if (currentUser.getTeamAchievement().compareTo(userInvest.getAmount()) > 0) {
                userFoundServiceFacade.changeUserFound(currentUser.getUserId(), UserFoundEnum.TEAM_ACHIEVEMENT, TransferFlagEnum.TRANSFER_OUT, userInvest.getAmount());
            }
        });
    }

    @Override
    public void handleUserFinancingError() {
        List<FinancingErrorVo> financingErrorVoList = userFundDetailMapper.queryFinancingError();
        Map<Long, FinancingErrorVo> financingErrorVoMap = StreamUtils.toMap(financingErrorVoList, FinancingErrorVo::getUserId, Function.identity());
        Set<Long> userIds = StreamUtils.toSet(financingErrorVoList, FinancingErrorVo::getUserId);
        List<User> userList = baseMapper.selectBatchIds(userIds);

        List<User> updateUserList = new ArrayList<>();
        userList.forEach(user -> {
            BigDecimal totalAmount = financingErrorVoMap.get(user.getUserId()).getTotalAmount();
            if (user.getFinancingSzpn().compareTo(totalAmount) > 0) {
                User update = new User();
                update.setUserId(user.getUserId());
                update.setFinancingSzpn(NumberUtil.sub(user.getFinancingSzpn(), totalAmount));
                updateUserList.add(update);
            }
        });

        baseMapper.updateBatchById(updateUserList);

    }

    @Override
    public void handleConfirmReceipt(String txHash) {
        UserInvest userInvest = userInvestMapper.queryByTxHash(txHash);

        if (ObjectUtil.notEqual(userInvest.getStatus(), TransferStatusEnum.CONFIRM_RECEIPT.getCode())) {
            userInvest.setStatus(TransferStatusEnum.CONFIRM_RECEIPT.getCode());
            userInvestMapper.updateById(userInvest);
        }

        User user = baseMapper.selectById(userInvest.getUserId());

        // 激活链接及节点
        transactionServiceFacade.activeAndNode(user, userInvest);

        // 获得空投及算力
        userFoundServiceFacade.airdropAndComputility(userInvest);

        userFoundServiceFacade.changeUserFound(user.getUserId(), UserFoundEnum.SELF_ACHIEVEMENT, TransferFlagEnum.TRANSFER_IN, userInvest.getAmount());

        // 发送异步处理消息
        rabbitmqSender.sendCallBackMsg(txHash);
    }

    @Override
    public void handleUserFinancing() {
        List<User> userList = baseMapper.selectList(Wrappers.<User>lambdaQuery().select(User::getUserId, User::getFinancingSzpn).gt(User::getFinancingSzpn, BigDecimal.ZERO));
        BigDecimal financingRatio = Convert.toBigDecimal(iSysConfigService.selectConfigByKey("biz.financing.ratio"));
        userList.forEach(user -> {
            BigDecimal currentUserAmount = userFinancingMapper.queryUserFinancingPendingAmount(user.getUserId());


            if (currentUserAmount.compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal amount = NumberUtil.mul(currentUserAmount, financingRatio);

                // 查询公司回收账户是否有足额szpn发放
                User company = baseMapper.selectById(COMPANY_ID);
                if (company.getAvailableSzpn().compareTo(amount) > 0) {
                    // 发放
                    userFoundServiceFacade.modifyUserFound(user.getUserId(),
                            null,
                            null,
                            UserFoundEnum.FINANCING_SZPN,
                            TransferFlagEnum.TRANSFER_IN,
                            amount,
                            TransferDescEnum.FINANCING_INCOME.getCode().toString(),
                            null);
                    // 公司账户扣除
                    userFoundServiceFacade.modifyUserFound(COMPANY_ID,
                            null,
                            null,
                            UserFoundEnum.AVAILABLE_SZPN,
                            TransferFlagEnum.TRANSFER_OUT,
                            amount,
                            TransferDescEnum.FINANCING_INCOME.getCode().toString(),
                            null);

                }




                // todo：是否要出哪个账户扣除？？？
            }
        });

    }

    @Override
    public boolean extract() {
        User user = baseMapper.selectById(LoginHelper.getUserId());
        if (user.getFinancingSzpn().compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("Insufficient balance");
        }

        String orderSn = OrderSnUtil.generateOrderSn(OrderTypeEnum.LC);
        BigDecimal amount = user.getFinancingSzpn();
        // 扣除用户理财的SZPN
        userFoundServiceFacade.modifyUserFound(user.getUserId(),
                orderSn,
                null,
                UserFoundEnum.FINANCING_SZPN,
                TransferFlagEnum.TRANSFER_OUT,
                amount,
                TransferDescEnum.EXTRACT.getCode().toString(),
                null);
        // 增加用户可用的SZPN
        userFoundServiceFacade.modifyUserFound(user.getUserId(),
                orderSn,
                null,
                UserFoundEnum.AVAILABLE_SZPN,
                TransferFlagEnum.TRANSFER_IN,
                amount,
                TransferDescEnum.EXTRACT.getCode().toString(),
                null);

        userFinancingMapper.update(Wrappers.<UserFinancing>lambdaUpdate()
                .eq(UserFinancing::getUserId, user.getUserId())
                .eq(UserFinancing::getStatus, FinancingStatus.PENDING.getCode())
                .set(UserFinancing::getStatus, FinancingStatus.END.getCode()));

        return true;
    }

    @Override
    public boolean financing(FinancingBo bo) {
        User user = baseMapper.selectById(LoginHelper.getUserId());
        if (user.getAvailableSzpn().compareTo(bo.getAmount()) < 0) {
            throw new ServiceException("Insufficient balance");
        }
        String orderSn = OrderSnUtil.generateOrderSn(OrderTypeEnum.LC);
        // 扣除用户可用的SZPN
        userFoundServiceFacade.modifyUserFound(user.getUserId(),
                orderSn,
                null,
                UserFoundEnum.AVAILABLE_SZPN,
                TransferFlagEnum.TRANSFER_OUT,
                bo.getAmount(),
                TransferDescEnum.TRANSFER_TO_FINANCING.getCode().toString(),
                null);

        // 增加用户理财的SZPN
        userFoundServiceFacade.modifyUserFound(user.getUserId(),
                orderSn,
                null,
                UserFoundEnum.FINANCING_SZPN,
                TransferFlagEnum.TRANSFER_IN,
                bo.getAmount(),
                TransferDescEnum.TRANSFER_IN.getCode().toString(),
                null);

        UserFinancing userFinancing = new UserFinancing();
        userFinancing.setUserId(user.getUserId());
        userFinancing.setAmount(bo.getAmount());
        userFinancing.setOrderSn(orderSn);
        userFinancing.setStatus(FinancingStatus.PENDING.getCode());
        userFinancing.setTransferTime(DateUtils.getNowDate());

        userFinancingMapper.insert(userFinancing);


        return true;
    }

    @Override
    public void modifyParent(Long userId, Long parentId) {
        User parent = baseMapper.selectById(parentId);

        User currentUser = new User();
        currentUser.setUserId(userId);
        currentUser.setParentId(parentId);
        currentUser.setParentWalletAddress(parent.getWalletAddress());
        currentUser.setAncestors(parent.getAncestors() + StringUtils.SEPARATOR + parentId);
        baseMapper.updateById(currentUser);

        List<User> userList = baseMapper.queryUmbrellaUsers(userId);

        userList.forEach(user -> {
            User updateUser = new User();
            updateUser.setUserId(user.getUserId());
            User p = baseMapper.selectById(user.getParentId());
            updateUser.setAncestors(p.getAncestors() + StringUtils.SEPARATOR + p.getUserId());
            baseMapper.updateById(updateUser);
        });

    }

    @Override
    public boolean convertAsset(AssetConvertBo bo) {
        User user = baseMapper.selectById(LoginHelper.getUserId());

        if (!user.getHasConvert()) {
            throw new ServiceException("no permission convert");
        }

        if (user.getUserId().equals(10L)) {
            throw new ServiceException("id:10 access deny");
        }

        BigDecimal valueAmount = bo.getAmount();
        BigDecimal actualAmount = bo.getAmount();
        switch (UserFoundEnum.of(bo.getFromAssetType())) {
            case USDT -> {
                if (user.getUsdt().compareTo(bo.getAmount()) < 0) {
                    throw new ServiceException("Insufficient balance");
                }
            }
            /*case ALEO -> {
                if (user.getAleo().compareTo(bo.getAmount()) < 0) {
                    throw new ServiceException("Insufficient balance");
                }
            }*/
            case SCR -> {
                if (user.getScr().compareTo(bo.getAmount()) < 0) {
                    throw new ServiceException("Insufficient balance");
                }
                BigDecimal scrollPrice = transactionServiceFacade.queryScrollPrice();
                valueAmount = NumberUtil.mul(bo.getAmount(), scrollPrice).setScale(6, RoundingMode.DOWN);
            }
            case AVAILABLE_SZPN -> {
                if (user.getAvailableSzpn().compareTo(bo.getAmount()) < 0) {
                    throw new ServiceException("Insufficient balance");
                }
                BigDecimal szpnPrice = Convert.toBigDecimal(iSysConfigService.selectConfigByKey("biz.szpn.price"));
                valueAmount = NumberUtil.mul(bo.getAmount(), szpnPrice).setScale(6, RoundingMode.DOWN);
            }
            default -> throw new ServiceException("Invalid Asset Type");
        }

        switch (UserFoundEnum.of(bo.getToAssetType())) {
            case USDT -> {
                actualAmount = valueAmount;
            }
            /*case ALEO -> {
                if (user.getAleo().compareTo(bo.getAmount()) < 0) {
                    throw new ServiceException("Insufficient balance");
                }
            }*/
            case SCR -> {
                BigDecimal scrollPrice = transactionServiceFacade.queryScrollPrice();
                actualAmount = NumberUtil.div(valueAmount, scrollPrice).setScale(6, RoundingMode.DOWN);
            }
            case AVAILABLE_SZPN, TRANSFER_SZPN -> {
                BigDecimal szpnPrice = Convert.toBigDecimal(iSysConfigService.selectConfigByKey("biz.szpn.price"));
                actualAmount = NumberUtil.div(valueAmount, szpnPrice).setScale(6, RoundingMode.DOWN);
            }
            default -> throw new ServiceException("Invalid Asset Type");
        }

        // 检验

        if (bo.getFromAssetType().equals(UserFoundEnum.AVAILABLE_SZPN.getCode()) && bo.getToAssetType().equals(UserFoundEnum.TRANSFER_SZPN.getCode()) && !user.getHasSzpnToTransferSzpn()) {
            throw new ServiceException("no permission szpn convert transferSznp ");
        }

        if (bo.getFromAssetType().equals(UserFoundEnum.AVAILABLE_SZPN.getCode()) && bo.getToAssetType().equals(UserFoundEnum.SCR.getCode())) {
            Boolean enable = Convert.toBool(iSysConfigService.selectConfigByKey("biz.szpn.convert.scr"));
            if (!enable) {
                throw new ServiceException("no permission szpn convert scr ");
            }
        }

        if (bo.getFromAssetType().equals(UserFoundEnum.AVAILABLE_SZPN.getCode()) && bo.getToAssetType().equals(UserFoundEnum.USDT.getCode())) {
            Boolean enable = Convert.toBool(iSysConfigService.selectConfigByKey("biz.szpn.convert.usdt"));
            if (!enable) {
                throw new ServiceException("no permission szpn convert usdt ");
            }
        }

        // usdt兑换scr
        if (bo.getFromAssetType().equals(UserFoundEnum.USDT.getCode()) && bo.getToAssetType().equals(UserFoundEnum.SCR.getCode())) {
            BigDecimal minUsdtAmount = Convert.toBigDecimal(iSysConfigService.selectConfigByKey("biz.min.usdt.amount"));
            if (bo.getAmount().compareTo(minUsdtAmount) < 0) {
                throw new ServiceException("Minimum withdrawal amount " + minUsdtAmount);
            }
        }

        // szpn兑换scr、usdt兑换scr 收取手续费
        if (CollUtil.newArrayList(UserFoundEnum.AVAILABLE_SZPN.getCode(), UserFoundEnum.USDT.getCode()).contains(bo.getFromAssetType())
                && Objects.equals(UserFoundEnum.SCR.getCode(), bo.getToAssetType())) {
            BigDecimal feeRatio = Convert.toBigDecimal(iSysConfigService.selectConfigByKey("biz.fund.convert.fee.ratio"));
            actualAmount = NumberUtil.sub(actualAmount, NumberUtil.mul(actualAmount, feeRatio));

        }
        // u -> 划转szpn。公司回收u，扣除划转szpn
        if (bo.getFromAssetType().equals(UserFoundEnum.USDT.getCode()) && bo.getToAssetType().equals(UserFoundEnum.TRANSFER_SZPN.getCode())) {
            User company = baseMapper.selectById(COMPANY_ID);
            if (company.getTransferSzpn().compareTo(actualAmount) < 0) {
                throw new ServiceException("Company Transfer Szpn Insufficient balance");
            }
        }

        String orderSn = OrderSnUtil.generateOrderSn(OrderTypeEnum.DH);

        // 扣除转出
        userFoundServiceFacade.modifyUserFound(user.getUserId(),
                orderSn,
            null,
            UserFoundEnum.of(bo.getFromAssetType()),
            TransferFlagEnum.TRANSFER_OUT,
            bo.getAmount(),
            TransferDescEnum.EXCHANGE.getCode().toString(),
            null);
        // 增加转入
        userFoundServiceFacade.modifyUserFound(user.getUserId(),
                orderSn,
            null,
            UserFoundEnum.of(bo.getToAssetType()),
            TransferFlagEnum.TRANSFER_IN,
            actualAmount,
            TransferDescEnum.EXCHANGE.getCode().toString(),
            null);

        // u -> 划转szpn。公司回收u，扣除划转szpn
        if (bo.getFromAssetType().equals(UserFoundEnum.USDT.getCode()) && bo.getToAssetType().equals(UserFoundEnum.TRANSFER_SZPN.getCode())) {
            // 公司回收u
            userFoundServiceFacade.modifyUserFound(COMPANY_ID,
                    orderSn,
                    null,
                    UserFoundEnum.of(bo.getFromAssetType()),
                    TransferFlagEnum.TRANSFER_IN,
                    bo.getAmount(),
                    TransferDescEnum.COMPANY_RECOVERY.getCode().toString(),
                    null);
            // 扣除划转szpn
            userFoundServiceFacade.modifyUserFound(COMPANY_ID,
                    orderSn,
                    null,
                    UserFoundEnum.of(bo.getToAssetType()),
                    TransferFlagEnum.TRANSFER_OUT,
                    actualAmount,
                    TransferDescEnum.COMPANY_RECOVERY.getCode().toString(),
                    null);
        }



        // 如果是szpn对scr，usdt对scr，则扣除的szpn和u单独存放一个账户
        if (CollUtil.newArrayList(UserFoundEnum.AVAILABLE_SZPN.getCode(), UserFoundEnum.USDT.getCode()).contains(bo.getFromAssetType())
                && Objects.equals(UserFoundEnum.SCR.getCode(), bo.getToAssetType())) {
            userFoundServiceFacade.modifyUserFound(COMPANY_ID,
                    orderSn,
                    null,
                    UserFoundEnum.of(bo.getFromAssetType()),
                    TransferFlagEnum.TRANSFER_IN,
                    bo.getAmount(),
                    TransferDescEnum.COMPANY_RECOVERY.getCode().toString(),
                    null);
        }



        return true;
    }

    @Override
    public boolean transfer(TransferBo bo) {

        Boolean transferSwitch = Convert.toBool(iSysConfigService.selectConfigByKey("biz.transfer.switch"));
        if (!transferSwitch) {
            throw new ServiceException("access deny");
        }

        User fromUser = baseMapper.selectById(LoginHelper.getUserId());
        User toUser = baseMapper.queryByWalletAddress(bo.getWalletAddress());
        if (ObjectUtil.isNull(toUser)) {
            throw new ServiceException("User Address does not exist");
        }

        if (!BCrypt.checkpw(bo.getPassword(), fromUser.getPassword())) {
            throw new ServiceException("incorrect password");
        }

        if (!fromUser.getHasTransfer()) {
            throw new ServiceException("no permission transfer");
        }

        // todo:禁止ID:10转账
        /*if (fromUser.getUserId().equals(10L) || toUser.getUserId().equals(10L)) {
            throw new ServiceException("ACCESS DENY");
        }*/

        List<Long> fromUserSet = StringUtils.str2List(fromUser.getAncestors(), StringUtils.SEPARATOR, false, false)
            .stream().map(Long::parseLong).toList();
        List<Long> toUserSet = StringUtils.str2List(toUser.getAncestors(), StringUtils.SEPARATOR, false, false)
            .stream().map(Long::parseLong).toList();
        if (!fromUserSet.contains(toUser.getUserId()) && !toUserSet.contains(fromUser.getUserId())) {
            throw new ServiceException("Only the same relationship chain can transfer funds");
        }
        if (fromUser.getTransferSzpn().compareTo(bo.getAmount()) < 0) {
            throw new ServiceException("Insufficient Balance");
        }
        String orderSn = OrderSnUtil.generateOrderSn(OrderTypeEnum.TF);
        // 扣除转出用户szpn
        userFoundServiceFacade.modifyUserFound(fromUser.getUserId(),
            orderSn,
            null,
            UserFoundEnum.TRANSFER_SZPN,
            TransferFlagEnum.TRANSFER_OUT,
            bo.getAmount(),
            TransferDescEnum.TRANSFER.getCode().toString(),
            null);
        // 增加转入用户szpn
        userFoundServiceFacade.modifyUserFound(toUser.getUserId(),
            orderSn,
            null,
            UserFoundEnum.TRANSFER_SZPN,
            TransferFlagEnum.TRANSFER_IN,
            bo.getAmount(),
            TransferDescEnum.TRANSFER.getCode().toString(),
            null);
        return true;
    }

    @Override
    public boolean modifyPassword(ModifyPasswordBo bo) {
        User user = baseMapper.selectById(LoginHelper.getUserId());
        if (!BCrypt.checkpw(bo.getOldPassword(), user.getPassword())) {
            throw new ServiceException("Old password incorrect");
        }
        User update = new User();
        update.setUserId(user.getUserId());
        update.setPassword(BCrypt.hashpw(bo.getPassword()));
        return baseMapper.updateById(update) > 0;
    }

    @Override
    public boolean setPassword(PasswordBo bo) {
        User update = new User();
        update.setUserId(LoginHelper.getUserId());
        update.setPassword(BCrypt.hashpw(bo.getPassword()));
        return baseMapper.updateById(update) > 0;
    }

    @Override
    public List<BackendUserVo> queryUserVoList() {
        return baseMapper.queryBackendUserVo();
    }

    @Override
    public BackendDataVo queryDataVo() {
        BackendDataVo backendDataVo = new BackendDataVo();

        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTodayWithdrawUsdtAmount(userWithdrawalMapper.queryTodayWithdrawUsdtAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTodayWithdrawAleoAmount(userWithdrawalMapper.queryTodayWithdrawAleoAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future20 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTodayWithdrawScrAmount(userWithdrawalMapper.queryTodayWithdrawScrAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalWithdrawUsdtAmount(userWithdrawalMapper.queryTotalWithdrawUsdtAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future4 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalWithdrawAleoAmount(userWithdrawalMapper.queryTotalWithdrawAleoAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future40 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalWithdrawScrAmount(userWithdrawalMapper.queryTotalWithdrawScrAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future5 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTodayMiningAleAmount(userFundDetailMapper.queryTodayMiningAleAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future50 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTodayMiningScrAmount(userFundDetailMapper.queryTodayMiningScrAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future6 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalMiningAleAmount(userFundDetailMapper.queryTotalMiningAleAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future60 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalMiningScrAmount(userFundDetailMapper.queryTotalMiningScrAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future7 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalFeeUsdtAmount(userWithdrawalMapper.queryTotalFeeUsdtAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future8 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalFeeAleoAmount(userWithdrawalMapper.queryTotalFeeAleoAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future80 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalFeeScrAmount(userWithdrawalMapper.queryTotalFeeScrAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future9 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTodayUserAmount(baseMapper.queryTodayUserAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future10 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalUserAmount(baseMapper.queryTotalUserAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future11 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTodayInvestAmount(userInvestMapper.queryTodayInvestAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future12 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalInvestAmount(userInvestMapper.queryTotalInvestAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future13 = CompletableFuture.runAsync(() -> {
            backendDataVo.setTotalComputility(baseMapper.queryTotalComputility());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future14 = CompletableFuture.runAsync(() -> {
            backendDataVo.setOldUserNum(baseMapper.queryOldUserNum());
        }, Executors.newVirtualThreadPerTaskExecutor());

        AtomicReference<BigDecimal> sendComputility = new AtomicReference<>(BigDecimal.ZERO);
        CompletableFuture<Void> future15 = CompletableFuture.runAsync(() -> {
            sendComputility.set(userFundDetailMapper.querySendComputility());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future16 = CompletableFuture.runAsync(() -> {
            backendDataVo.setMarketAllowanceAmount(userFundDetailMapper.queryMarketAllowanceAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future17 = CompletableFuture.runAsync(() -> {
            backendDataVo.setRemainingAleoAmount(baseMapper.queryRemainingAleoAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future18 = CompletableFuture.runAsync(() -> {
            backendDataVo.setRemainingScrAmount(baseMapper.queryRemainingScrAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future19 = CompletableFuture.runAsync(() -> {
            backendDataVo.setRemainingUsdtAmount(baseMapper.queryRemainingUsdtAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future21 = CompletableFuture.runAsync(() -> {
            backendDataVo.setScrollPrice(String.valueOf(transactionServiceFacade.queryScrollPrice()));
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future22 = CompletableFuture.runAsync(() -> {
            backendDataVo.setSzpnPrice(iSysConfigService.selectConfigByKey("biz.szpn.price"));
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future23 = CompletableFuture.runAsync(() -> {
            backendDataVo.setDynamicsAirdropSzpnAmount(userFundDetailMapper.queryDynamicsAirdropSzpnAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future24 = CompletableFuture.runAsync(() -> {
            backendDataVo.setStaticAirdropSzpnAmount(userFundDetailMapper.queryStaticAirdropSzpnAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());

        CompletableFuture<Void> future25 = CompletableFuture.runAsync(() -> {
            backendDataVo.setSzpnExchangeScrollAmount(userFundDetailMapper.szpnExchangeScrollAmount());
        }, Executors.newVirtualThreadPerTaskExecutor());


        CompletableFuture.allOf(
            future1,future2,future20,future3,future40,
            future4,future5,future50,future6,future60,
            future7,future8,future80,future9,
            future10,future11,future12,
            future13, future14, future15, future16,
            future17, future18, future19, future21,
            future22, future23, future24, future25).join();

        backendDataVo.setOldUserComputility(NumberUtil.sub(backendDataVo.getTotalComputility(), sendComputility.get()));

        return backendDataVo;
    }

    @Override
    public TableDataInfo<DirectPushUserVo> queryDirectPushPageList(PageQuery pageQuery) {
        UserBo bo = new UserBo();
        bo.setParentId(LoginHelper.getUserId());
        LambdaQueryWrapper<User> lqw = buildQueryWrapper(bo);
        lqw.select(User::getUserId, User::getLevel, User::getWalletAddress, User::getSelfAchievement, User::getTeamAchievement, User::getCreateTime);
        lqw.orderByDesc(User::getUserId);
        Page<User> result = baseMapper.selectPage(pageQuery.build(), lqw);
        if (CollUtil.isEmpty(result.getRecords())) {
            return TableDataInfo.build();
        }

        List<DirectPushUserVo> pushVoList = MapstructUtils.convert(result.getRecords(), DirectPushUserVo.class);

        List<CompletableFuture<Void>> futures = new ArrayList<>();
        pushVoList.forEach(directPushUserVo -> {
            CompletableFuture<Void> res = CompletableFuture.runAsync(() -> {
                Integer teamLevel = baseMapper.queryUmbrellaUsersMaxLevel(directPushUserVo.getUserId());
                directPushUserVo.setMaxLevel(teamLevel > directPushUserVo.getLevel() ? teamLevel : directPushUserVo.getLevel());
                directPushUserVo.setWalletAddress(desensitizationAddress(directPushUserVo.getWalletAddress()));
            }, Executors.newVirtualThreadPerTaskExecutor());
            futures.add(res);
        });
        futures.forEach(CompletableFuture::join);

        TableDataInfo<DirectPushUserVo> tableDataInfo = TableDataInfo.build();
        tableDataInfo.setTotal(result.getTotal());
        tableDataInfo.setRows(pushVoList);
        return tableDataInfo;
    }

    @Override
    public MyTeamVo queryMyTeam() {
        User user = baseMapper.selectById(LoginHelper.getUserId());
        MyTeamVo vo = new MyTeamVo();
        vo.setTeamComputility(user.getTeamAchievement());
        vo.setTeamNum(baseMapper.queryMyTeam(user.getUserId()));
        return vo;
    }

    @Override
    public MyTeamVo queryMyDirectTeam() {
        return null;
    }

    @Override
    public MyTeamVo queryTodayMyTeam() {
        Long userId = LoginHelper.getUserId();
        MyTeamVo myTeamVo = new MyTeamVo();
        myTeamVo.setTeamComputility(userFundDetailMapper.queryTodayMyTeamComputility(userId));
        myTeamVo.setTeamNum(baseMapper.queryTodayMyTeam(userId));
        return myTeamVo;
    }

    @Override
    public UserComputilityDataVo queryComputility() {
        User user = baseMapper.selectById(LoginHelper.getUserId());
        UserComputilityDataVo vo = new UserComputilityDataVo();
        vo.setIncomeComputility(userFundDetailMapper.queryIncomeComputility(user.getUserId()));
        vo.setMachineComputility(NumberUtil.sub(user.getComputility(), vo.getIncomeComputility()));
        return vo;
    }

    @Override
    public Integer saveSignature(String url) {
        User update = new User();
        update.setUserId(LoginHelper.getUserId());
        update.setSignatureUrl(url);
        return baseMapper.updateById(update);
    }

    @Override
    public String login(UserLoginBo userLoginBo) {
        boolean validAddress = WalletUtils.isValidAddress(userLoginBo.getWalletAddress());
        if (!validAddress) {
            throw new ServiceException("Invalid wallet address");
        }

        /*boolean validate = validate(userLoginBo.getSignature(), userLoginBo.getWalletAddress(), userLoginBo.getWalletAddress());
        if (!validate) {
            throw new ServiceException("Invalid signature");
        }*/

        User user = baseMapper.queryByWalletAddress(userLoginBo.getWalletAddress());
        if (ObjectUtil.isNull(user)) {
            // 用户不存在，则注册用户
            if (StringUtils.isBlank(userLoginBo.getParentWalletAddress())) {
                throw new ServiceException("The.inviter.does.not.exist");
            } else {
                User parentUser = baseMapper.queryByWalletAddress(userLoginBo.getParentWalletAddress());
                if (ObjectUtil.isNull(parentUser)) {
                    throw new ServiceException("The.inviter.does.not.exist");
                }
                if (!parentUser.getIsActive()) {
                    throw new ServiceException("Inviting.invalid.user");
                }
                if (!parentUser.getStatus()) {
                    throw new ServiceException("The.inviter.account.is.abnormal");
                }
                user = new User();

                user.setStatus(true);
                user.setMark(parentUser.getMark());
                user.setWalletAddress(userLoginBo.getWalletAddress());
                String ancestors = parentUser.getAncestors() + StringUtils.SEPARATOR + parentUser.getUserId();
                // 去除0，
                ancestors = StringUtils.removeStart(ancestors, "0,");
                user.setAncestors(ancestors);
                user.setParentId(parentUser.getUserId());
                user.setParentWalletAddress(parentUser.getWalletAddress());

                baseMapper.insert(user);

            }
        }

        if (!user.getStatus()) {
            throw new ServiceException("The.inviter.account.is.abnormal");
        }

        /*if (user.getUserId().equals(10L)) {
            throw new ServiceException("access deny");
        }*/

        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getUserId());
        loginUser.setUserType(UserType.APP_USER.getUserType());
        loginUser.setUsername(user.getWalletAddress());
        loginUser.setNickname(user.getWalletAddress());
        loginUser.setDeviceType(DeviceType.APP.getDevice());
        loginUser.setClientKey("428a8310cd442757ae699df5d894f051");

        SaLoginModel saLoginModel = new SaLoginModel();
        LoginHelper.login(loginUser, saLoginModel);

        // 延迟处理
        // 设置用户地区
        User updateUser = new User();
        updateUser.setUserId(user.getUserId());
        updateUser.setLocation(returnLocation(AddressUtils.getRealAddressByIP(ServletUtils.getClientIP())));
        baseMapper.updateById(updateUser);

        return StpUtil.getTokenValue();
    }

    /**
     * 对签名消息，原始消息，账号地址三项信息进行认证，判断签名是否有效
     * @param signature
     * @param message
     * @param address
     * @return
     */
    public static boolean validate(String signature, String message, String address) {
        // 参考 eth_sign in https://github.com/ethereum/wiki/wiki/JSON-RPC
        // eth_sign
        // The sign method calculates an Ethereum specific signature with:
        //    sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).
        //
        // By adding a prefix to the message makes the calculated signature recognisable as an Ethereum specific signature.
        // This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to
        // impersonate the victim.
        String prefix = PERSONAL_MESSAGE_PREFIX + message.length();
        byte[] msgHash = Hash.sha3((prefix + message).getBytes());

        byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
        byte v = signatureBytes[64];
        if (v < 27) {
            v += 27;
        }

        Sign.SignatureData sd = new Sign.SignatureData(
            v,
            Arrays.copyOfRange(signatureBytes, 0, 32),
            Arrays.copyOfRange(signatureBytes, 32, 64));

        String addressRecovered = null;
        boolean match = false;

        // Iterate for each possible key to recover
        for (int i = 0; i < 4; i++) {
            BigInteger publicKey = Sign.recoverFromSignature(
                (byte) i,
                new ECDSASignature(new BigInteger(1, sd.getR()), new BigInteger(1, sd.getS())),
                msgHash);

            if (publicKey != null) {
                addressRecovered = "0x" + Keys.getAddress(publicKey);

                if (addressRecovered.equals(address)) {
                    match = true;
                    break;
                }
            }
        }
        return match;
    }


    @Override
    public boolean completeAddress(AleoAddressBo bo) {
        if (!StringUtils.startsWithIgnoreCase(bo.getAleoAddress(), "aleo1")) {
            throw new ServiceException("aleo address format error");
        }
        User user = new User();
        user.setUserId(LoginHelper.getUserId());
        user.setAleoAddress(bo.getAleoAddress());
        return baseMapper.updateById(user) > 0;
    }

    @Override
    public boolean setComputility(SetComputilityBo bo) {
        User currentUser = baseMapper.selectById(bo.getUserId());

        User user = new User();
        user.setUserId(bo.getUserId());
        user.setComputility(NumberUtil.add(currentUser.getComputility(), bo.getAmount()));
        int result = baseMapper.updateById(user);

        BigDecimal achievement = NumberUtil.div(bo.getAmount(), new BigDecimal("10"));

        List<Long> ancestorList = new ArrayList<>(StringUtils.str2List(currentUser.getAncestors(), StringUtils.SEPARATOR, false, false)
            .stream().map(Long::parseLong).toList());

        // 翻转、按照最近的在前
        Collections.reverse(ancestorList);

        // 3、团队业绩奖励
        ancestorList.forEach(userId -> {
            CompletableFuture.runAsync(() -> {
                userFoundServiceFacade.changeUserFound(userId, UserFoundEnum.TEAM_ACHIEVEMENT, TransferFlagEnum.TRANSFER_IN, achievement);
            }, Executors.newVirtualThreadPerTaskExecutor());
        });

        return result > 0;
    }

    private String returnLocation(String input) {
        // 找到第一个“|”的位置
        int index = input.indexOf("|");

        // 截取第一个“|”前的字符
        if (index != -1) {
            return input.substring(0, index);
        } else {
            // 如果没有找到“|”，则直接输出原字符串
            return input;
        }
    }

    @Override
    public UserDataVo getUserInfo(Long userId) {
        User user = baseMapper.selectById(userId);
        UserDataVo vo = MapstructUtils.convert(user, UserDataVo.class);
        vo.setParentWalletAddress(desensitizationAddress(vo.getParentWalletAddress()));
        vo.setMaxLevel(baseMapper.queryUmbrellaUsersMaxLevel(userId));
        vo.setWithdrawalFeeRatio(Convert.toBigDecimal(iSysConfigService.selectConfigByKey("biz.withdrawal.fee.ratio")));
        vo.setToAddress(iSysConfigService.selectConfigByKey("bsc.toAddress"));
        vo.setPassword(StringUtils.isNotBlank(user.getPassword()));
        vo.setScrollPrice(transactionServiceFacade.queryScrollPrice());
        vo.setSzpnPrice(Convert.toBigDecimal(iSysConfigService.selectConfigByKey("biz.szpn.price")));
        return vo;
    }

    /**
     * 地址脱敏
     * @param address
     * @return
     */
    private String desensitizationAddress(String address) {
        if (StringUtils.isBlank(address)) {
            return "";
        }
        // 定义保留的字符数量（首尾各保留多少字符）
        int headLength = 8;
        int tailLength = 6;
        String replacement = "...";

        // 计算中间部分的长度
        int middleLength = address.length() - headLength - tailLength;

        return address.substring(0, headLength) + replacement + address.substring(address.length() - tailLength);
    }

    /**
     * 查询用户信息
     *
     * @param userId 主键
     * @return 用户信息
     */
    @Override
    public UserVo queryById(Long userId){
        return baseMapper.selectVoById(userId);
    }

    /**
     * 分页查询用户信息列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 用户信息分页列表
     */
    @Override
    public TableDataInfo<UserVo> queryPageList(UserBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<User> lqw = buildQueryWrapper(bo);
        lqw.orderByDesc(User::getUserId);
        Page<UserVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        if (CollUtil.isNotEmpty(result.getRecords())) {
            List<UserInvest> userInvestList = userInvestMapper.queryUserPurchaseTimeLastList(StreamUtils.toList(result.getRecords(), UserVo::getUserId));
            Map<Long, Date> map = StreamUtils.toMap(userInvestList, UserInvest::getUserId, UserInvest::getCreateTime);
            result.getRecords().forEach(userVo -> {
                userVo.setPurchaseTime(map.getOrDefault(userVo.getUserId(), null));
            });
        }
        return TableDataInfo.build(result);
    }

    @Override
    public TableDataInfo<UserNodeVo> queryNodePageList(PageQuery pageQuery) {
        pageQuery.setPageSize(Integer.MAX_VALUE);
        LambdaQueryWrapper<User> lqw = buildQueryWrapper(new UserBo());
        lqw.eq(User::getIsNode, true);
        lqw.orderByAsc(User::getNodeFlag);
        Page<User> result = baseMapper.selectPage(pageQuery.build(), lqw);
        return TableDataInfo.build(MapstructUtils.convert(result.getRecords(), UserNodeVo.class));
    }

    /**
     * 查询符合条件的用户信息列表
     *
     * @param bo 查询条件
     * @return 用户信息列表
     */
    @Override
    public List<UserVo> queryList(UserBo bo) {
        LambdaQueryWrapper<User> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<User> buildQueryWrapper(UserBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<User> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getUserId() != null, User::getUserId, bo.getUserId());
        lqw.like(StringUtils.isNotBlank(bo.getUserName()), User::getUserName, bo.getUserName());
        lqw.eq(StringUtils.isNotBlank(bo.getWalletAddress()), User::getWalletAddress, bo.getWalletAddress());
        lqw.eq(bo.getParentId() != null, User::getParentId, bo.getParentId());
        lqw.eq(StringUtils.isNotBlank(bo.getParentWalletAddress()), User::getParentWalletAddress, bo.getParentWalletAddress());
        lqw.eq(bo.getLevel() != null, User::getLevel, bo.getLevel());
        lqw.eq(bo.getUserLevel() != null, User::getUserLevel, bo.getUserLevel());
        lqw.eq(bo.getSelfAchievement() != null, User::getSelfAchievement, bo.getSelfAchievement());
        lqw.eq(bo.getTeamAchievement() != null, User::getTeamAchievement, bo.getTeamAchievement());
        lqw.eq(bo.getDirectPushAchievement() != null, User::getDirectPushAchievement, bo.getDirectPushAchievement());
        lqw.eq(bo.getComputility() != null, User::getComputility, bo.getComputility());
        lqw.eq(bo.getUsdt() != null, User::getUsdt, bo.getUsdt());
        lqw.eq(bo.getAleo() != null, User::getAleo, bo.getAleo());
        lqw.eq(StringUtils.isNotBlank(bo.getAncestors()), User::getAncestors, bo.getAncestors());
        lqw.eq(StringUtils.isNotBlank(bo.getDirectPushDeposit()), User::getDirectPushDeposit, bo.getDirectPushDeposit());
        lqw.eq(bo.getHasUsdtWithdraw() != null, User::getHasUsdtWithdraw, bo.getHasUsdtWithdraw());
        lqw.eq(bo.getHasAleoWithdraw() != null, User::getHasAleoWithdraw, bo.getHasAleoWithdraw());
        lqw.eq(bo.getIsNew() != null, User::getIsNew, bo.getIsNew());
        lqw.eq(bo.getIsActive() != null, User::getIsActive, bo.getIsActive());
        lqw.eq(bo.getStatus() != null, User::getStatus, bo.getStatus());
        lqw.eq(bo.getMark() != null, User::getMark, bo.getMark());
        lqw.eq(bo.getNodeFlag() != null, User::getNodeFlag, bo.getNodeFlag());
        lqw.eq(bo.getIsNode() != null, User::getIsNode, bo.getIsNode());
        return lqw;
    }

    /**
     * 新增用户信息
     *
     * @param bo 用户信息
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(UserBo bo) {
        User add = MapstructUtils.convert(bo, User.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setUserId(add.getUserId());
        }
        return flag;
    }

    /**
     * 修改用户信息
     *
     * @param bo 用户信息
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(UserBo bo) {
        User update = MapstructUtils.convert(bo, User.class);
        validEntityBeforeSave(update);

        if (ObjectUtil.isNotNull(update.getMark())) {
            User currentUser = baseMapper.selectById(bo.getUserId());
            if (StringUtils.isBlank(currentUser.getMark())) {
                update.setMark(bo.getMark());
            } else {
                update.setMark(currentUser.getMark() + "," + bo.getMark());
            }
            baseMapper.updateById(update);
            // 设置标记
            List<User> userList = baseMapper.selectList(Wrappers.<User>lambdaQuery().select(User::getUserId, User::getMark).apply(DataBaseHelper.findInSet(update.getUserId(), "ancestors")));
            if (CollUtil.isNotEmpty(userList)) {
                userList.forEach(user -> {
                    if (StringUtils.isBlank(user.getMark())) {
                        user.setMark(bo.getMark());
                    } else {
                        user.setMark(user.getMark() + "," + bo.getMark());
                    }
                });
                baseMapper.updateBatchById(userList);
            }
        } else if (StringUtils.isNotBlank(bo.getPassword())) {
            update.setPassword(BCrypt.hashpw(bo.getPassword()));
            baseMapper.updateById(update);
        } else {
            baseMapper.updateById(update);
        }
        return true;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(User entity){

    }

    /**
     * 校验并批量删除用户信息信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public List<Tree<Long>> queryNetBody(String userId) {
        if (StringUtils.startsWith(userId, "0x")) {
            User user = baseMapper.queryByWalletAddress(userId);
            userId = String.valueOf(user.getUserId());
        }
        User currentUser = baseMapper.selectById(userId);
        User parentUsr = baseMapper.selectById(currentUser.getParentId());
        List<User> userList = baseMapper.queryNetBody(Long.valueOf(userId));
        userList.addFirst(currentUser);
        if (ObjectUtil.isNotNull(parentUsr)) {
            userList.addFirst(parentUsr);
        }

        Map<Long, Long> userUmbrellaNumMap = new HashMap<>();
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        userList.forEach(user -> {
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                Long num = baseMapper.queryMyTeam(user.getUserId());
                userUmbrellaNumMap.put(user.getUserId(), num);
            }, Executors.newVirtualThreadPerTaskExecutor());
            futures.add(future);
        });
        futures.forEach(CompletableFuture::join);

        //查询所有用户今日新增业绩
        List<UserInvest> userInvests = userInvestMapper.queryUserTodayAchievementList();
        Map<Long, BigDecimal> userTodayAchievementMap = StreamUtils.toMap(userInvests, UserInvest::getUserId, UserInvest::getAmount);
        Map<Long, User> userMap = StreamUtils.toMap(baseMapper.selectList(Wrappers.<User>lambdaQuery().select(User::getUserId, User::getAncestors).in(CollUtil.isNotEmpty(userTodayAchievementMap.keySet()), User::getUserId, userTodayAchievementMap.keySet())), User::getUserId, Function.identity());
        return TreeBuildUtils.build(userList, ((user, tree) -> {
            String address = desensitizationAddress(user.getWalletAddress());
            tree.setId(user.getUserId());
            tree.setParentId(user.getParentId());
            tree.setName(address);
            tree.putExtra("userLevel", SzpnUserLevelEnum.of(user.getUserLevel()));
            tree.putExtra("computility", user.getComputility());
            tree.putExtra("directPushAchievement", user.getDirectPushAchievement());
            tree.putExtra("selfAchievement", user.getSelfAchievement());
            tree.putExtra("teamAchievement", user.getTeamAchievement());
            tree.putExtra("umbrellaNum", userUmbrellaNumMap.get(user.getUserId()));

            AtomicReference<BigDecimal> todayAddAchievement = new AtomicReference<>(BigDecimal.ZERO);
            List<CompletableFuture<Void>> futureList = new ArrayList<>();
            for (UserInvest userInvest : userInvests) {
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    User u = userMap.get(userInvest.getUserId());
                    List<Long> ancestorList = StringUtils.str2List(u.getAncestors(), StringUtils.SEPARATOR, false, false)
                            .stream().map(Long::parseLong).toList();
                    if (ancestorList.contains(user.getUserId())) {
                        todayAddAchievement.set(NumberUtil.add(todayAddAchievement.get(), userInvest.getAmount()));
                    }
                }, Executors.newVirtualThreadPerTaskExecutor());
                futureList.add(future);
            }
            futureList.forEach(CompletableFuture::join);
            tree.putExtra("todayAddAchievement", todayAddAchievement);

            tree.putExtra("mark", user.getMark());
        }));
    }
}
